#pragma once
#include <iostream>
#include <string>
#include <time.h>
#include <stdarg.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <pthread.h>

namespace ns_log
{
    bool gissave = false;
    pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
    #define logname "log.txt"
    enum
    {
        INFO = 0,
        DEBUG,
        WARNNING,
        ERROR,
        FATAL
    };

    std::string GetLevel(int level)
    {
        switch (level)
        {
        case 0:
            return "INFO";
            break;
        case 1:
            return "DEBUG";
            break;
        case 2:
            return "WARNNING";
            break;
        case 3:
            return "ERROR";
            break;
        case 4:
            return "FATAL";
            break;
        default:
            return "NONE";
            break;
        }
    }

    std::string GetTime()
    {
        time_t t = time(nullptr);
        struct tm *tt = localtime(&t);
        char buffer[1024];
        snprintf(buffer, sizeof(buffer), "%d-%d-%d %d:%d:%d",
                 tt->tm_year + 1900, tt->tm_mon + 1, tt->tm_mday, tt->tm_hour, tt->tm_min, tt->tm_sec);

        return buffer;
    }

    void PrintToFile(std::string message)
    {
        FILE* f = fopen(logname,"a");
        if(f == nullptr)
            exit(1);
        else
        {
            fprintf(f,"Message: %s",message.c_str());
        }
        fclose(f);
    }

    void LOGString(const std::string name, int line, int level, bool issave, const char *format, ...)
    {
        std::string levelstr = GetLevel(level);
        std::string timestr = GetTime();
        pid_t selfid = getpid();

        va_list va;
        va_start(va, format);

        char buffer[1024];
        vsnprintf(buffer, sizeof(buffer), format, va);

        va_end(va);


        std::string message = "[" + timestr + "]" + "[" + levelstr + "]" +
                              "[" + std::to_string(selfid) + "]" +
                              "[" + name + "]" + "[" + std::to_string(line) + "] " + buffer + "\n";
        pthread_mutex_lock(&mutex);
        if(issave == false)
            std::cout << message <<std::endl;
        else
            PrintToFile(message);
        pthread_mutex_unlock(&mutex);
    }


    #define LOG(level,format, ...)  \
    do                              \
    {                               \
        LOGString(__FILE__,__LINE__,level,gissave,format,##__VA_ARGS__);                            \
    }while(0)                       \

    #define EnableFile()            \
    do                              \
    {                               \
        gissave = true;             \
    }while(0)                       \

    #define EnableCout()            \
    do                              \
    {                               \
        gissave = false;            \
    } while(0);                     \
    

}